#include "./MysqlHandler.h"

namespace DbConnPool
{
    // 初始化数据库连接
    MysqlHandler::MysqlHandler()
    {
        // 分配或初始化与mysql_real_connect()相适应的MYSQL对象
        // 如果mysql是NULL指针，该函数将分配、初始化、并返回新对象
        this->conn_ = mysql_init(nullptr);

        // 设置字符编码，可以储存中文
        mysql_set_character_set(this->conn_, "utf8");
    }

    // 释放数据库连接
    MysqlHandler::~MysqlHandler()
    {
        if (this->conn_ != nullptr)
        {
            mysql_close(this->conn_);
        }

        // 释放结果集
        this->freeResult();
    }

    // 释放结果集
    void MysqlHandler::freeResult()
    {
        if (this->result_)
        {
            mysql_free_result(this->result_);
            this->result_ = nullptr;
        }
    }

    // 连接数据库
    bool MysqlHandler::connect(const std::string &ip, const unsigned short port,
                               const std::string &user, const std::string &password,
                               const std::string dbName)
    {
        // 尝试与运行在主机上的MySQL数据库引擎建立连接
        MYSQL *ptr = mysql_real_connect(this->conn_,
                                        ip.c_str(), user.c_str(), password.c_str(),
                                        dbName.c_str(), port, nullptr, 0);
        return ptr != nullptr;
    }

    // 更新数据库：包括 insert update delete 操作
    bool MysqlHandler::update(const std::string &sql)
    {
        if (mysql_query(this->conn_, sql.c_str())) // 注意：查询失败返回非0值
        {
            return false;
        }
        return true;
    }

    // 查询数据库
    bool MysqlHandler::query(const std::string &sql)
    {
        // 查询前确保结果集为空
        this->freeResult();

        if (mysql_query(this->conn_, sql.c_str())) // 注意：查询失败返回非0值
        {
            return false;
        }
        // 储存结果集(这是一个二重指针)
        this->result_ = mysql_store_result(this->conn_);
        return true;
    }

    // 遍历查询得到的结果集
    bool MysqlHandler::next()
    {
        if (this->result_ == nullptr)
        {
            return false;
        }

        this->row_ = mysql_fetch_row(this->result_);
        if (this->row_ == nullptr)
        {
            return false;
        }
        return true;
    }

    // 得到结果集中的字段值
    std::string MysqlHandler::getValue(int index)
    {
        int fieldCount = mysql_num_fields(this->result_);
        if (index < 0 || index >= fieldCount)
        {
            // 获取字段索引不合法，返回空字符串
            return std::string{};
        }

        // 考虑到储存的可能是二进制字符串，其中含有'\0'
        // 那么我们无法获得完整字符串，因此需要获取字符串头指针和字符串长度
        char *value = this->row_[index];
        unsigned long length = mysql_fetch_lengths(this->result_)[index];
        return std::string(value, length);
    }

    // 事务操作，参数true自动提交，false手动提交
    bool MysqlHandler::useAutoTransaction(bool flag)
    {
        // true  自动提交，false 手动提交
        return mysql_autocommit(this->conn_, flag);
    }

    // 提交事务
    bool MysqlHandler::commit()
    {
        return mysql_commit(this->conn_);
    }

    // 事务回滚
    bool MysqlHandler::rollbock()
    {
        return mysql_rollback(this->conn_);
    }

    // 刷新起始的空闲时间点，没有在构造或connect()时调用，而是上层调用
    void MysqlHandler::refreshAliveTime()
    {
        // 获取时间戳
        this->beginTime_ = std::chrono::steady_clock::now();
    }

    // 计算连接存活的总时长
    long long MysqlHandler::getAliveTime()
    {
        // 获取时间段（当前时间戳 - 创建时间戳）
        std::chrono::nanoseconds period = std::chrono::steady_clock::now() - this->beginTime_;
        // 纳秒 -> 毫秒，高精度向低精度转换需要duration_cast
        std::chrono::milliseconds millisec = std::chrono::duration_cast<std::chrono::milliseconds>(period);
        // 返回毫秒数量
        return millisec.count();
    }
} // namespace DbConnPool